/*
	The Raja Toolkit.
	Copyright (C) 2011 Raja-Toolkit Foundation

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 3.0 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "gles2_internal.hpp"
#include "../gpu_types.hpp"

namespace raja
{
namespace render
{
using namespace std;
using namespace raja::math;

///////////////////////////////////////////////////////////////////////////////
// GLSL types
///////////////////////////////////////////////////////////////////////////////
/// translation table from unitform type to string
boost::unordered_map<GPU_DATA_TYPE, std::string>	_data_type_to_string;

///
/// fill in the glsl type to string translation table
///
bool	_init_data_type_to_string()
{
	_data_type_to_string[GDT_REAL32]		= "float";
	_data_type_to_string[GDT_VEC2]			= "vec2";
	_data_type_to_string[GDT_VEC3]			= "vec3";
	_data_type_to_string[GDT_VEC4]			= "vec4";
	_data_type_to_string[GDT_SINT32]		= "int";
	_data_type_to_string[GDT_IVEC2]			= "ivec2";
	_data_type_to_string[GDT_IVEC3]			= "ivec3";
	_data_type_to_string[GDT_IVEC4]			= "ivec4";
	_data_type_to_string[GDT_BOOL]			= "bool";
	_data_type_to_string[GDT_BVEC2]			= "bool2";
	_data_type_to_string[GDT_BVEC3]			= "bool3";
	_data_type_to_string[GDT_BVEC4]			= "bool4";
	_data_type_to_string[GDT_MAT2]			= "mat2";
	_data_type_to_string[GDT_MAT3]			= "mat3";
	_data_type_to_string[GDT_MAT4]			= "mat4";
	_data_type_to_string[GDT_SAMPLER2]		= "sampler2D";
	_data_type_to_string.rehash(_data_type_to_string.size());
	return true;
}

/// we need a dummy to init the table
bool	_dummy_init_of_data_type_name = _init_data_type_to_string();

///
/// get the name of the uniform type
/// @param type uniform type enum
/// @return name of glsl the uniform type
///
string get_name_of_type(GPU_DATA_TYPE type)
{
	if( _data_type_to_string.find(type) == _data_type_to_string.end() )
	{
		cout << "ERROR: Invalid Type" << endl;
		return "";
	}

	return _data_type_to_string[type];
}

///////////////////////////////////////////////////////////////////////////////

/// alignment data table
boost::unordered_map<GPU_DATA_TYPE, size_t>	_data_type_align;

///
/// fill in the glsl type to string translation table
///
bool	_init_data_type_align()
{
	/// @todo this really depends on the system, but mostly it should be 4 float
	//size_t	align	= 4;

	_data_type_align[GDT_REAL32]		= sizeof(real32);
	_data_type_align[GDT_VEC2]			= sizeof(vec2);
	_data_type_align[GDT_VEC3]			= sizeof(vec3);
	_data_type_align[GDT_VEC4]			= sizeof(vec4);
	_data_type_align[GDT_SINT32]		= sizeof(sint32);
	_data_type_align[GDT_IVEC2]			= sizeof(ivec2);
	_data_type_align[GDT_IVEC3]			= sizeof(ivec3);
	_data_type_align[GDT_IVEC4]			= sizeof(ivec4);
	_data_type_align[GDT_BOOL]			= sizeof(bool);
	_data_type_align[GDT_BVEC2]			= sizeof(bvec2);
	_data_type_align[GDT_BVEC3]			= sizeof(bvec3);
	_data_type_align[GDT_BVEC4]			= sizeof(bvec4);
	_data_type_align[GDT_MAT2]			= sizeof(mat2);
	_data_type_align[GDT_MAT3]			= sizeof(mat3);
	_data_type_align[GDT_MAT4]			= sizeof(mat4);
	_data_type_align[GDT_SAMPLER2]		= sizeof(uint32);
	_data_type_align.rehash(_data_type_align.size());

	return true;
}

/// we need a dummy to init the table
bool	_dummy_init_of_data_align = _init_data_type_align();

///
/// get the name of the uniform type
/// @param type uniform type enum
/// @return name of glsl the uniform type
///
size_t get_size_of_type(GPU_DATA_TYPE type)
{
	if( _data_type_align.find(type) == _data_type_align.end() )
	{
		cout << "ERROR: Invalid Type" << endl;
		return 0;
	}

	return _data_type_align[type];
}

///////////////////////////////////////////////////////////////////////////////

/// translation table from GLSL enum type to string
boost::unordered_map<GLenum, GPU_DATA_TYPE>	_enum_type_to_prog_type;

///
/// fill in the glsl type to string translation table
///
bool	_init_enum_type_to_prog_type()
{
	_enum_type_to_prog_type[GL_FLOAT]		= GDT_REAL32;
	_enum_type_to_prog_type[GL_FLOAT_VEC2]	= GDT_VEC2;
	_enum_type_to_prog_type[GL_FLOAT_VEC3]	= GDT_VEC3;
	_enum_type_to_prog_type[GL_FLOAT_VEC4]	= GDT_VEC4;
	_enum_type_to_prog_type[GL_INT]			= GDT_SINT32;
	_enum_type_to_prog_type[GL_INT_VEC2]	= GDT_IVEC2;
	_enum_type_to_prog_type[GL_INT_VEC3]	= GDT_IVEC3;
	_enum_type_to_prog_type[GL_INT_VEC4]	= GDT_IVEC4;
	_enum_type_to_prog_type[GL_BOOL]		= GDT_BOOL;
	_enum_type_to_prog_type[GL_BOOL_VEC2]	= GDT_BVEC2;
	_enum_type_to_prog_type[GL_BOOL_VEC3]	= GDT_BVEC3;
	_enum_type_to_prog_type[GL_BOOL_VEC4]	= GDT_BVEC4;
	_enum_type_to_prog_type[GL_FLOAT_MAT2]	= GDT_MAT2;
	_enum_type_to_prog_type[GL_FLOAT_MAT3]	= GDT_MAT3;
	_enum_type_to_prog_type[GL_FLOAT_MAT4]	= GDT_MAT4;
	_enum_type_to_prog_type[GL_SAMPLER_2D]	= GDT_SAMPLER2;
	_enum_type_to_prog_type.rehash(_enum_type_to_prog_type.size());

	return true;
}

/// we need a dummy to init the table
bool	_dummy_init_of_enum_type_to_prog_type = _init_enum_type_to_prog_type();

///
/// get the name of the uniform type
/// @param GLES enum uniform type
/// @return the uniform type
///
GPU_DATA_TYPE gles_type_to_prog_type(GLenum type)
{
	if( _enum_type_to_prog_type.find(type) == _enum_type_to_prog_type.end() )
	{
		cout << "ERROR: Invalid GLES type" << endl;
		return GDT_ERROR;
	}

	return _enum_type_to_prog_type[type];
}

}	// namespace render
}	// namespace raja
